/*
# File    :   bit_operate.c
# Git     :   https://gitee.com/schips/
*/

#include <stdio.h>
#define SET_BIT(value, bit)     ((value)  |  (1 << (bit)))
#define CLR_BIT(value, bit)     ((value)  & ~(1 << (bit)))
#define GET_BIT(value, bit)     ((((value)>>(bit)) &  0x01)==1)
#define SET_BYTE(value, byte)   ((value)  |  (byte))
#define CLR_BYTE(value, byte)   ((value)  & ~(byte))
#define GET_BYTE(value, byte)   (((value) &  (byte)) == (byte) )


/*
 * 由于处理位的时候不知道是哪种数据类型，所以用宏会比用 inline 函数好
 *
 * */

#if 1
//消去x最后一位的1  :   x&(x-1)
#define dislodge_last_one(x) ((x)&((x) - 1))

/*  用途
 *可以用来检测一个数是不是2的幂次。如果一个数x是2的幂次，那么x>0且x的二进制中只有一个1,所以用x&(x-1)把1消去，应该返回0，如果返回了非0值，证明不是2的幂次

计算一个整数二进制中1的个数
因为1可以不断的通过x&(x-1)这个操作消去，所以当最后的值变成0的时候，也就求出了二进制中1的个数

如果将整数A转换成整数B,需要改变多少个比特位.
思考将整数A转换为B，如果A和B在第i（0<=i<32）个位上相等，则不需要改变这个BIT位，如果在第i位上不相等，则需要改变这个BIT位。所以问题转化为了A和B有多少个BIT位不相同。联想到位运算有一个异或操作，相同为0，相异为1，所以问题转变成了计算A异或B之后这个数中1的个数
 * */
#endif

// 判断奇偶
#define is_odd(x) ((x)&1)

// 求平均数（只适用于整数）
#define average(x, y) ((x)&(y))+(((x)^(y))>>1)

// 将所有的位 置一
#define set_all_one(x) ((x)+(~x))

// 求绝对值
#define ABS_INT64(x)        ((x) ^ ((x) >> 63)) - ((x) >> 63)
#define ABS_INT32(x)        ((x) ^ ((x) >> 31)) - ((x) >> 31)
#define ABS_INT16(x)        ((x) ^ ((x) >> 15)) - ((x) >> 15)
#define ABS_INT8(x)         ((x) ^ ((x) >>  7)) - ((x) >>  7)


#if 1
// 优化： 取模操作优化（仅适用于除数是2的幂次方）
#define MOD(a,b) (a)&((b)-1)
#endif

#if 1
// 移位实现整数除法
int Division(int y,int x)
{
	int sum=0;
	int i=0;
	while( y > x) //向左移位直到 x >= y
	{
		x = x << 1;
		i++;      //记录左移的次数
	}

	x = x>> 1;    // 使 x <= y
	i--;

	while(i >= 0)
	{
		if(y >= x)
		{
			sum += 1 << i;
			y -= x;
		}
		x = x >> 1;
		--i;
	}

	return sum;
}
#endif

// 求 bits 中 1的个数
unsigned int count_bits_in_bytes(unsigned int a)
{
    a = ((a & 0xAAAA) >>1) + (a & 0x5555);
    a = ((a & 0xCCCC) >>2) + (a & 0x3333);
    a = ((a & 0xF0F0) >>4) + (a & 0x0F0F);
    a = ((a & 0xFF00) >>8) + (a & 0x00FF);
    return a;
}

// 获取连续的bit(截取变量的部分连续位)
#if 1
#define   getBits(x, end, start)   ( (x & ~(~(0U)<<((end)-(start) + 1))<<(start)) >> (start) )
#else
unsigned int getBits(unsigned int bit, int end, int start)
{
    unsigned int b;
    int i,bi;

    for(i = 0, b = 0, bi = 0; i < ((sizeof(bit))<< 3); i++)
    {
        if(i <= end && i >= start)
        {
            b |= ((bit >> i) & 1) << bi;
            bi++;
        }
    }

    return b;
}
#endif

int main(int argc, char *argv[])
{
    unsigned char x= 0x11;
    unsigned short a =34520;

    printf("x = %x\n", x);
    //dislodge_last_one(&x);
    x = dislodge_last_one(x);
    printf("dislodge_last_one(x) : %x\n", x);
    if(is_odd(x))
    {
        printf("is_odd(%d) Yes\n", x);
    }
    printf("average(1,35) : %d\n", average(1,35));

    printf("set_all_one = %x\n", set_all_one(5));
    x = CLR_BIT(x, 5);
    printf("CLR_BIT(x, 5) : %x\n", x);

    // 优化 取模
    printf("MOD : 20 %% 16 = %d, MOD(20,16) = %d)\n",20%16, MOD(20,16) );
    // 优化除法
	printf(" 90 / 5 = %d \n", Division(90,5));
	printf(" 89 / 5 = %d, %d \n", Division(89,5));

    printf("count_bits_in_bytes(0xff) : %d\n", count_bits_in_bytes(0xff));

    //printf("getBits\n");
    printf("getBits(0x11223344, 31, 24): [0x%02x]\n",  getBits(0x11223344, 31, 24));
    printf("getBits(0x11223344, 23, 16): [0x%02x]\n",  getBits(0x11223344, 23, 16));
    printf("getBits(0x11223344, 15,  8): [0x%02x]\n",  getBits(0x11223344, 15,  8));
    printf("getBits(0x11223344,  7,  0): [0x%02x]\n",  getBits(0x11223344,  7,  0));
    return 0;
}

